﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Taobao.Top.Api;
using System.Threading;
using System.IO; 
using System.Collections;

namespace Taobao.Common
{
    public abstract class TaobaoProcessor<TShop>:IProcessor,IDisposable
        where TShop:class,IShop,new()
    {
        protected static readonly object lockObj =new object();
        public const int ThreadSleepTick =500;
        public const int DefaultPageSize = 50;
        protected const string LogFile = "log.txt";

        #region Ctor

        public TaobaoProcessor(string requestUrl,string moduleName,TShop shop)
            :this(requestUrl,moduleName,shop.ID)
        { 
        }

        public TaobaoProcessor(string requestUrl,string moduleName,short shopid)
        {
            Initialize();
            ModuleName = moduleName;
            RequestUrl =requestUrl;
            ShopID = shopid;
            if (Shop != null)
            {
                Client = new TopXmlRestClient(RequestUrl, AppKey, AppSecret);
            }
            else
            {
                OutputWriter.WriteLine("对不起，没有该店铺的信息！", OutputFormatType.Error);
            }
        }

        public TaobaoProcessor(string requestUrl,string moduleName,short shopid, IOutputWriter textWriter)
            :this(requestUrl,moduleName,shopid)
        {
            OutputWriter = textWriter;
        }

        #endregion

        #region Initialize
        protected virtual void Initialize() { }
        #endregion

        #region Fields
        protected Thread JobThread;
         

        #endregion

        #region Events

        public event ProcessStartedEventHanlder ProcessStarted;
        public event ProcessCompletedEventHandler ProcessCompleted;
        public event Action<TShop> ShopChanged;

        public Func<TShop, int> SwitchShop;

        #endregion

        #region Properties
        public string SessionKey
        {
            get { return Shop.SessionKey; } 
        }

        public IOutputWriter OutputWriter
        {
            get;
            set;
        }

        protected string AppKey
        {
            get
            {
                return Shop.AppKey;
            }
        }

        protected string AppSecret
        {
            get
            {
                return Shop.AppSecret;
            }
        }

        public string ShopName
        {
            get
            {
                return Shop.Name;
            }
        }

        public TopXmlRestClient Client
        {
            get;
            private set;
        }

        public ProcessStatus Status
        {
            get;
            set;
        }

        public string ModuleName { get; set; }

        public string RequestUrl{get;set;}

        public ILogger Logger { get; set; }
            
        protected TShop Shop;

        private short shopID;
        public short ShopID
        {
            get
            {
                return shopID;
            }
            protected set
            {
                shopID = value;
                Shop = GetShop(value);
                if (Shop != null)
                {
                    Client = new TopXmlRestClient(RequestUrl, AppKey, AppSecret); 
                }
                if (ShopChanged != null && Shop != null)
                    ShopChanged(Shop);
            }
        }
        
        public Action<string> UpdateStatus;

        #region Abstract        
        protected abstract TShop GetShop(short shopID);
        #endregion
        #endregion

        #region Virtual Methods

        protected virtual void OnProcessCompleted()
        {
            try
            {
                OutputWriter.WriteLine("店铺" + ShopName + "更新程序运行结束", OutputFormatType.Title);
                ExcuteUpdateStatus("店铺"+ShopName+"更新程序运行结束");
                Logger.Write(ModuleName, LogType.Normal, "店铺" + ShopName + "更新程序运行结束", "", Shop);
                if (ProcessCompleted != null)
                {
                    ProcessCompleted(this, new TaobaoProcessorEventArgs(ShopID,ShopName));
                }
            }
            catch { }
        }

        protected virtual void OnProcessStarted()
        {
            try
            {
                OutputWriter.WriteLine("店铺" + ShopName + "更新程序运行开始", OutputFormatType.Title);
                ExcuteUpdateStatus("店铺"+ShopName+"更新程序运行开始");
                Logger.Write(ModuleName, LogType.Normal, "店铺"+ShopName+"更新程序运行开始", "", Shop);
                if (ProcessStarted != null)
                {
                    ProcessStarted(this, new TaobaoProcessorEventArgs(ShopID, ShopName));
                }
                OutputWriter.WriteLine(string.Empty);
            }
            catch { }
        }

        protected virtual void DoExcuteJob() { }

        #endregion

        #region Main Methods 

        public void ExcuteJob()
        {
            DoExcuteJob();
        }
          
        #endregion

        #region IProcessor Members

        public virtual void Start()
        {
            try
            {
                JobThread = null;
                JobThread = new Thread(new ThreadStart(ExcuteJob));
                JobThread.IsBackground = true;
                JobThread.Priority = ThreadPriority.Lowest;
                JobThread.Start();
                OutputWriter.WriteLine("API处理启动...", OutputFormatType.Title);
                Status = ProcessStatus.Started;
            }
            catch { }
        }

        public virtual void Suspend()
        {
            try
            {
                Thread.Sleep(ThreadSleepTick);
                JobThread.Suspend();
                Status = ProcessStatus.Suspended;
                Thread.Sleep(ThreadSleepTick);
                OutputWriter.WriteLine("API处理暂停...", OutputFormatType.Title);
            }
            catch { }
        }

        public virtual void Resume()
        {
            try
            {
                Thread.Sleep(ThreadSleepTick);
                JobThread.Resume();
                Thread.Sleep(ThreadSleepTick);
                Status = ProcessStatus.Resumed;
                OutputWriter.WriteLine("API处理继续...", OutputFormatType.Title);
            }
            catch { }
        }

        public virtual void Stop()
        {
            try
            {
                if (JobThread.IsAlive)
                {
                    JobThread.Abort();
                }
            }
            catch { }
            finally
            {
                OutputWriter.WriteLine("API处理停止！", OutputFormatType.Title);
                //JobThread = null; 
                Status = ProcessStatus.Stoped;
                Thread.Sleep(ThreadSleepTick);
            }
        }

        #endregion

        #region Clear Output

        public void Clear()
        {
            if (Status == ProcessStatus.Resumed
                || Status == ProcessStatus.Started)
            {
                try
                {
                    Thread.Sleep(ThreadSleepTick);
                    JobThread.Suspend();

                    //LogToFile();

                    OutputWriter.Clear();
                    Thread.Sleep(ThreadSleepTick);
                    JobThread.Resume();
                }
                catch { }
            }
            else
            {
                try
                {
                    Thread.Sleep(ThreadSleepTick);
                    OutputWriter.Clear();
                }
                catch { }
            }
        }

        #endregion

        #region Exception Handler

        protected void HandleException(string displayMessage, Exception e)
        {
            HandleException(displayMessage, e, true);
        }

        protected void HandleException(string displayMessage, Exception e,bool display)
        {
            try
            {
                var dException = new TaobaoException(displayMessage, e);
                if (display)
                {
                    OutputWriter.WriteLine(displayMessage, OutputFormatType.Exception);
                }
                //Log the exception to DB
                Logger.Write(ModuleName, LogType.Exception,
                    "DisplayMessage: " + displayMessage + ";ExceptionMessage:" + e.Message+";InnerException:"+((e.InnerException==null)?"NULL":e.InnerException.Message),
                    e.StackTrace.Substring(0, e.StackTrace.Length > 1900 ? 1900 : e.StackTrace.Length), Shop);
            }
            catch(Exception innerEx) 
            {
                using(var writer =new StreamWriter(LogFile,true))
                {
                    writer.WriteLine(string.Format("店铺:{0}", ShopName));
                    writer.WriteLine(string.Format("日志异常:{0}", DateTime.Now));
                    writer.WriteLine(string.Format("新异常原因:{0}", innerEx.Message));
                    writer.WriteLine(string.Format("Stack:{0}", innerEx.StackTrace));
                    writer.WriteLine(string.Format("原异常:{0}", displayMessage));
                    writer.WriteLine(string.Format("原异常原因:{0}", e.Message));
                    writer.WriteLine(string.Format("Stack:{0}", e.StackTrace));
                    writer.WriteLine();
                }
            }
        }

        #endregion

        #region Update Status

        protected void ExcuteUpdateStatus(string statusInfo)
        {
            try
            {
                if (Status == ProcessStatus.Started || Status == ProcessStatus.Resumed)
                {
                    if (UpdateStatus != null)
                    {
                        UpdateStatus.Invoke(statusInfo);
                        //UpdateStatus(statusInfo);
                    }
                }
                //Logger.Write(ModuleName, LogType.Normal, statusInfo, statusInfo, Shop);
            }
            catch { }
        }

        #endregion

        #region Assist Methods

        protected DateTime? ConvertDateTime(string datetime)
        {
            DateTime value = DateTime.MinValue;
            if (!String.IsNullOrEmpty(datetime))
            {
                DateTime.TryParse(datetime, out value);   
            }
            if (value != DateTime.MinValue)
                return value;
            return null;
        }
        
        protected void LogStatisticsEnd(string contentTitle, long total, long success)
        {
            try
            {
                StringBuilder logBuilder = new StringBuilder();
                logBuilder.AppendFormat("{0}处理结束。", contentTitle);
                OutputWriter.WriteLine(logBuilder.ToString(), OutputFormatType.Title);

                if (total > 0)
                {
                    logBuilder = new StringBuilder();
                    logBuilder.AppendFormat("总共：{0} 条{1}需要处理，成功处理了{2}条，失败了 {3}条。", total, contentTitle, success, total - success);
                    OutputWriter.WriteLine(logBuilder.ToString(), OutputFormatType.Title);
                }
                OutputWriter.WriteLine("");
            }
            catch { }
        }

        protected void LogStatisticsStart(string contentTitle, long total)
        {
            try
            {
                StringBuilder logBuilder = new StringBuilder();
                if (total > 0)
                {
                    logBuilder.AppendFormat("总共：{0} 条{1}需要处理...", total, contentTitle);
                }
                else
                {
                    logBuilder.AppendFormat("没有{0}需要处理。", contentTitle);
                }
                OutputWriter.WriteLine(logBuilder.ToString(), OutputFormatType.Title);
            }
            catch { }
        }


        protected virtual int ProcessPageList<T>(string contentName, int pageSize, Taobao.Top.Api.Domain.PageList<T> firstContentList, Func<int, Taobao.Top.Api.Domain.PageList<T>> getNextContentList, Func<T,long, bool> processAction)
        {
            return ProcessPageList<T>(contentName, pageSize, firstContentList, getNextContentList, processAction, firstContentList.TotalResults);
        }

        protected virtual int ProcessPageList<T>(string contentName, int pageSize, Taobao.Top.Api.Domain.PageList<T> firstContentList, Func<int, Taobao.Top.Api.Domain.PageList<T>> getNextContentList, Func<T,long, bool> processAction, long totalCount)         
        {
            var success = 0;
            try
            {
                var pageCount = (int)(totalCount / pageSize) + ((totalCount % pageSize > 0) ? 1 : 0);
                OutputWriter.WriteLine("将要获取的" + contentName + "的总页数为:" + pageCount + "页，每页:" + pageSize + "条。", OutputFormatType.Title);
                var currentPageNo = 1;
                var index = 0;
                var currentContentList = firstContentList;
                do
                {
                    try
                    {
                        OutputWriter.WriteLine("第" + currentPageNo + "页：", OutputFormatType.Title);
                        index = 0;
                        foreach (T t in currentContentList.Content)
                        {
                            index++;
                            if (processAction(t, (currentPageNo - 1) * pageSize + index))
                                success++;
                        }
                    }
                    catch (Exception e)
                    {
                        HandleException("更新第" + currentPageNo + "页的" + contentName + "失败。", e);
                        Thread.Sleep(1000);
                    }
                    currentPageNo++;
                    try
                    {
                        currentContentList = getNextContentList(currentPageNo);
                    }
                    catch(Exception ep) 
                    {
                        continue;
                    }
                } while (currentPageNo <= pageCount);
            }
            catch (Exception e)
            {
                HandleException("处理获取淘宝数据分页出错", e);
            }
            return success;
        }

        protected virtual int ProcessQueryable<T>(string contentName, int pageSize, IEnumerable<T> totalContentList, Func<T,long, bool> processAction, long totalCount)
        {
            var success = 0;
            try
            {
                var pageCount = (int)(totalCount / pageSize) + ((totalCount % pageSize > 0) ? 1 : 0);
                OutputWriter.WriteLine("将要获取的" + contentName + "的总页数为:" + pageCount + "页，每页:" + pageSize + "条。", OutputFormatType.Title);
                var currentPageNo = 1;
                var index = 0;
                var currentContentList = totalContentList.Skip((currentPageNo - 1) * pageSize).Take(currentPageNo * pageSize);
                do
                {
                    try
                    {
                        OutputWriter.WriteLine("第" + currentPageNo + "页：", OutputFormatType.Title);
                        index = 0;
                        foreach (T t in currentContentList)
                        {
                            index++;
                            if (processAction(t, (currentPageNo - 1) * pageSize + index))
                                success++;
                        }
                    }
                    catch (Exception e)
                    {
                        HandleException("更新第" + currentPageNo + "页的" + contentName + "失败。", e);
                        Thread.Sleep(1000);
                    }
                    currentPageNo++;
                    try
                    {
                        currentContentList = totalContentList.Skip((currentPageNo - 1) * pageSize).Take(currentPageNo * pageSize);
                    }
                    catch (Exception ep)
                    {
                        continue;
                    }
                } while (currentPageNo <= pageCount);
            }
            catch(Exception e) 
            {
                HandleException("处理查询数据分页出错", e);
            }
            return success;
        }

        protected virtual int ProcessQueryable<T>(string contentName, int pageSize, Func<int,int,IEnumerable<T>> getNextPage, Func<T, long, bool> processAction, long totalCount)
        {
            var success = 0;
            try
            {
                var pageCount = (int)(totalCount / pageSize) + ((totalCount % pageSize > 0) ? 1 : 0);
                OutputWriter.WriteLine("将要获取的" + contentName + "的总页数为:" + pageCount + "页，每页:" + pageSize + "条。", OutputFormatType.Title);
                var currentPageNo = 1;
                var index = 0;
                var currentContentList = getNextPage(pageSize, currentPageNo);
                do
                {
                    try
                    {
                        OutputWriter.WriteLine("第" + currentPageNo + "页：", OutputFormatType.Title);
                        index = 0;
                        foreach (T t in currentContentList)
                        {
                            index++;
                            if (processAction(t, (currentPageNo - 1) * pageSize + index))
                                success++;
                        }
                    }
                    catch (Exception e)
                    {
                        HandleException("更新第" + currentPageNo + "页的" + contentName + "失败。", e);
                        Thread.Sleep(1000);
                    }
                    currentPageNo++;
                    try
                    {
                        currentContentList = getNextPage(pageSize, currentPageNo);
                    }
                    catch (Exception ep)
                    {
                        continue;
                    }
                } while (currentPageNo <= pageCount);
            }
            catch (Exception e)
            {
                HandleException("处理查询数据分页出错", e);
            }
            return success;
        }
        protected virtual void UpdateTaskIncrement(string title,DateTime updateDate, long total, Func<long> updateTaskAction)
        {
            long success = 0;
            ExcuteUpdateStatus(string.Format("开始更新{0}变化的{1}:{2}条", updateDate.ToShortDateString(), title,total));
            try
            {
                OutputWriter.WriteLine(string.Format("开始更新所有{0}...", title), OutputFormatType.Title);

                LogStatisticsStart(title, total);
                success = updateTaskAction();
            }
            catch (Exception e)
            {
            }
            finally
            {
                LogStatisticsEnd(title, total, success);
            }
        }
        protected virtual void UpdateTask(string title, long total, Func<long> updateTaskAction)
        {
            long success = 0;
            ExcuteUpdateStatus(string.Format("开始更新{0}:{1}条", title,total));
            try
            {
                OutputWriter.WriteLine(string.Format("开始更新所有{0}...", title), OutputFormatType.Title);
                //List<long> dTradeIdList = new List<long>();
                //using (Model.taobaodbEntities entities = ResourceManager.LoadEntity())
                //{
                //    dTradeIdList = (from t in entities.Trade
                //                    where t.Shop.ShopId == ShopID
                //                    && t.created != null
                //                    && t.created.Value > DateTime.Now.AddMonths(-12)
                //                    && t.status == Constants.PurchaseOrder_WAIT_SELLER_SEND_GOODS
                //                    select t.tid).ToList();
                //}

                LogStatisticsStart(title, total);
                success = updateTaskAction();
                //foreach (long tradeId in dTradeIdList)
                //{
                //    success += UpdatePurchaseOrders(tradeId) ? 1 : 0;

                //}
            }
            catch (Exception e)
            {
            }
            finally
            {
                LogStatisticsEnd(title, total, success);
            }
        }
        #endregion

        #region Dispose

        public void Dispose()
        {
            if (JobThread != null && JobThread.IsAlive)
            {
                try
                {
                    JobThread.Abort();
                }
                catch { }
                finally
                {
                    JobThread = null;
                    GC.SuppressFinalize(this);
                    GC.Collect();
                }
            }
        }

        #endregion

        #region  Log to File

        public void LogToFile()
        {
            try
            {
                string logFolder = Path.Combine(Environment.CurrentDirectory, "/log");
                if (!Directory.Exists(logFolder))
                {
                    Directory.CreateDirectory(logFolder);
                }
                string fileName = logFolder + "/" + DateTime.Now.ToString("yyyy_mm_dd_hh_MM_SS") + ShopID.ToString();
                Logger.WriteLogToFile(fileName, OutputWriter.GetOutputText());
            }
            catch { }
        }

        #endregion
    }

    
}
